//
//  IJKPlayerView.swift
//  Personal
//
//  Created by Ans on 2017/7/31.
//  Copyright © 2017年 Mengxuan Chen. All rights reserved.
//

import UIKit
import IJKMediaFramework

class PlayerCtrl: IJKFFMoviePlayerController {
    
    weak var playerView: UIView!
    
    deinit {
        print("deinit PlayerCtrl")
    }
    
    override init!(contentURLString aUrlString: String!, with options: IJKFFOptions!) {
        super.init(contentURLString: aUrlString, with: options)
    }
    
    override init!(contentURL aUrl: URL!, with options: IJKFFOptions!) {
        super.init(contentURL: aUrl, with: options)
        
        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        playerView = view
        scalingMode = .aspectFit
        //        shouldAutoplay = true
    }
}

protocol VideoPlayViewDelegate: NSObjectProtocol {
    func videoPlayViewOrientation(_ isFull: Bool)
    
    func videoPlayViewTouchesBegan(_ isHidden: Bool)
}

class IJKPlayerView: UIView {
    
    var player: PlayerCtrl?
    
    lazy var centerPlayBtn: UIButton = { [weak self] in
        let btn = UIButton(type: .custom)
        btn.bounds = CGRect(x: 0, y: 0, width: 40, height: 40)
        btn.autoresizingMask = [.flexibleTopMargin,.flexibleLeftMargin,.flexibleBottomMargin,.flexibleRightMargin]
        btn.setBackgroundImage(UIImage(named: "frame_video_play_icon")!, for: .normal)
        btn.addTarget(self, action: #selector(centerPlayBtnClick(_ :)), for: .touchUpInside)
        return btn
        }()
    
//    // 全屏调用代理
    weak var delegate: VideoPlayViewDelegate?
    
    // 记录播放按钮的点击
    var isPlaying = true
    
    // 区分手动点区产生的暂停，有时加载时也会产生暂停
    var isTapPause = false
    
    // 定时器更新进度用
    var displayLink: CADisplayLink!{
        
        didSet{
            
            
        }
    }
    
    
    var isFullSelected: Bool = false {
        didSet {
            playerToolView.fullBtn.isSelected = isFullSelected
        }
    }
    
    var playbackTime: TimeInterval! {
        didSet {
            //print(playbackTime)
        }
        
    }
    
//    var kiPhoneXScreenHTrack : CGFloat {
//        get{
//            if UIScreen.main.bounds.size.height == 812.0 {
//                return UIScreen.main.bounds.size.height - 34.0
//            }else{
//                return UIScreen.main.bounds.size.height
//            }
//        }
//    }
//
//    var kiPhoneXTabbarH : CGFloat{
//        get{
//            if UIScreen.main.bounds.size.height == 812.0 {
//                return 34
//            }else{
//                return 0
//            }
//        }
//    }
    
//    var shouldAutoplay: Bool!
    
    // 传出在播放完成、手击暂停的情况，用于外部旋转后则不再自动播放
    var playSpecificStatusCallback: ((Bool)->())?

    
    // 播放工具条
    lazy var playerToolView: PlayerControlView = { [weak self] in
        var kiPhoneXScreenHTrack: CGFloat = UIScreen.main.bounds.size.height
        if UIScreen.main.bounds.size.height == 812.0 {
            kiPhoneXScreenHTrack = UIScreen.main.bounds.size.height - 34.0
        }
        var kiPhoneXTabbarH: CGFloat = 0.0
        if UIScreen.main.bounds.size.height == 812.0 {
            kiPhoneXTabbarH = 34.0
        }
        
        // 初始化
        let toolView = PlayerControlView.loadNib()
        toolView.frame = CGRect(x: 0, y: kiPhoneXScreenHTrack - kiPhoneXTabbarH - 48, width: (self?.bounds.width)!, height: 48)
        // 点击播放按钮
        toolView.playBtnCallback = { [weak self] isSelected in
            
            // play or pause
            guard let state = self?.player?.playbackState else { return }
            switch state {
            case .stopped:
//                if self?.playerToolView.progressSlider.value == 1.0 {
//                }
                // 判断是否有滑动过 slider
                if (self?.playerToolView.sliderView.value)! >= Float(1) {
                    // currentPlaybackTime  归零 重新播放
                    self?.player?.currentPlaybackTime = 0
                    self?.playbackTime = 0
                }else {
                    guard let duration = self?.player?.duration else { return }
                    let progressValue = self?.playerToolView.sliderView.value
                    let currentPlaybackTime = duration * TimeInterval(progressValue!)
                    self?.player?.currentPlaybackTime = currentPlaybackTime
                }
                self?.player?.play()
                self?.isPlaying = true
            case .playing:
                
                self?.playSpecificStatusCallback?(false)
                
                self?.isTapPause = true
                
                self?.player?.pause()
                self?.isPlaying = false
                
            case .paused:
                self?.player?.play()
                self?.isPlaying = true
                
            case .interrupted:
                self?.player?.play()
                self?.isPlaying = true
                
            case .seekingForward:
                print("playBtnCallback 前移")
                
            case .seekingBackward:
                print("playBtnCallback 后移")
            }
        }
        
        // 全屏按钮点击回调
        toolView.fullBtnCallback = { [weak self] isFull in
            
            // 调用代理
            self?.delegate?.videoPlayViewOrientation(isFull)
        }
        

        //滑动结束
        toolView.sliderTouchCancelCallback = { [weak self] progressValue in
            
            // 播放
//            if (self?.isPlaying)! {
            
                guard let duration = self?.player?.duration else { return }
                let currentPlaybackTime = duration * TimeInterval(progressValue)
                self?.player?.currentPlaybackTime = currentPlaybackTime
                self?.playbackTime = currentPlaybackTime
                print("滑动进度\(progressValue)")
                print("滑动时间\(currentPlaybackTime)")
            
                self?.player?.play()
//                self?.addDisplayLink()
//            }
            
        }
        
        //滑动开始
        toolView.sliderTouchBeganCallback = {[weak self] progressValue in
            
            if (self?.isPlaying)! {//暂停
                self?.player?.pause()
                self?.removeDisplayLink()
            }
        }
        
        // 滑动改变
        toolView.sliderValueChangedCallback = { [weak self] progressValue in

            guard let duration = self?.player?.duration else { return }
            let currentPlaybackTime = duration * TimeInterval(progressValue)
            self?.playbackTime =  currentPlaybackTime
            // 更新时间
            DispatchQueue.main.async {
                self?.playerToolView.timeLabel.text = self?.videoTimeStr(currentPlaybackTime, duration: duration)
            }
            
        }
        
        return toolView
        }()
    
    override var bounds: CGRect {
        didSet {
            centerPlayBtn.center = CGPoint(x: bounds.midX, y: bounds.midY)
//            player?.playerView.bounds = bounds
        }
    }
    
    override var frame: CGRect {
        didSet {
            centerPlayBtn.center = CGPoint(x: bounds.midX, y: bounds.midY)
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        
        autoresizingMask = [.flexibleWidth,.flexibleHeight]
        
        // 2. 添加工具条
        addSubview(playerToolView)
        
        // 4. 添加 通知
        installMovieNotiObservers()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    func pausePlay(_ stopCallback:((TimeInterval)->())?) {
        
        if playbackTime != nil {
            stopCallback?(playbackTime)
        }

        removeDisplayLink()
        
        player?.stop()
        player?.playerView.removeFromSuperview()
        // 关闭播放器
        player?.shutdown()// 销毁第一步
        player = nil// 销毁第二步🔚
    }
    
    deinit {

        // 移除定时器
        removeDisplayLink()
        
        // 关闭播放器
        player?.stop()
        player?.playerView.removeFromSuperview()
        player?.shutdown()
        player = nil
//        IJKAudioKit.sharedInstance 
        
        // 5. 移除通知
        let notiCenter = NotificationCenter.default
        notiCenter.removeObserver(self, name: NSNotification.Name.IJKMPMoviePlayerLoadStateDidChange, object: player)
        notiCenter.removeObserver(self, name: NSNotification.Name.IJKMPMoviePlayerPlaybackDidFinish, object: player)
        notiCenter.removeObserver(self, name: NSNotification.Name.IJKMPMediaPlaybackIsPreparedToPlayDidChange, object: player)
        notiCenter.removeObserver(self, name: NSNotification.Name.IJKMPMoviePlayerPlaybackStateDidChange, object: player)
        
        print("IJK deinit")
    }
}

// MARK:- centerPlayBtn
extension IJKPlayerView {
    @objc func centerPlayBtnClick(_ btn: UIButton) {
        
        // play or pause
        guard let state = player?.playbackState else { return }
        switch state {
        case .stopped:
            if self.playerToolView.sliderView.value >= Float(1) {
                // currentPlaybackTime  归零 重新播放
                self.player?.currentPlaybackTime = 0
                self.playbackTime = 0
            }else {
                guard let duration = self.player?.duration else { return }
                let progressValue = self.playerToolView.sliderView.value
                let currentPlaybackTime = duration * TimeInterval(progressValue)
                self.player?.currentPlaybackTime = currentPlaybackTime
            }
            self.player?.play()
            self.isPlaying = true
            
        case .playing:
            player?.pause()
            isPlaying = false
            
        case .paused:
            player?.play()
            isPlaying = true
            
        case .interrupted:
            player?.play()
            isPlaying = true
            
        case .seekingForward:
            print("playBtnCallback 前移")
            
        case .seekingBackward:
            print("playBtnCallback 后移")
        }

    }
}

// MARK:- 定时器
extension IJKPlayerView {

    func addDisplayLink() {
        guard displayLink == nil else { return }
        displayLink = CADisplayLink(target: self, selector: #selector(update))
        displayLink.add(to: .main, forMode: .defaultRunLoopMode)
    }
    
    func removeDisplayLink() {
        guard displayLink != nil else { return }
        displayLink.invalidate()
        displayLink = nil
    }
    
    @objc func update() {
        
        DispatchQueue.main.async {
            // 更新时间
            self.playerToolView.timeLabel.text = self.timeString()
            
            // 更新进度条
            if let durSec = self.player?.duration, let curSec = self.player?.currentPlaybackTime {
                
                guard !curSec.isNaN else { return }
                guard !durSec.isNaN else { return }
                print("-----%ld-----%ld",self.playbackTime,curSec)
                if self.playbackTime > curSec {
                    return
                }
                if  curSec > 0 {
                    print("更新时间3>>>>>\(curSec)")
                    
                    self.playbackTime = curSec
                }
                
                self.playerToolView.progress = Float(curSec / durSec)
                self.playerToolView.playBtn.isSelected = true
//                self.playerToolView.sliderView.value = Float(curSec / durSec)
//                print("durSec:\(durSec), curSec:\(curSec)")
            }
        }
    }
}

// MARK:- 点击事件
extension IJKPlayerView {
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        let allTouches:NSSet = (event?.allTouches)! as NSSet
        let touch:UITouch = allTouches.anyObject() as! UITouch
        
        //屏蔽工具条的点击
        if touch.view is PlayerControlView {
            return
        }
        let point:CGPoint = touch.location(in:touch.view)
        //限制点击范围在工具条之上
        if point.y < UIScreen.main.bounds.size.height - 60 {
            singTapAction()
        }
        
    }
    
    func singTapAction()  {
        
        let isHidden = !self.playerToolView.isHidden
        
        delegate?.videoPlayViewTouchesBegan(isHidden)
        
//        UIView.animate(withDuration: 0.25) {
//            self.playerToolView.isHidden = isHidden
//        }
    }
}

// MARK:- 播放
extension IJKPlayerView {

    
    func playLocalVideo(_ fileURL: URL, currentPlaybackTime: TimeInterval, isAutoPlay: Bool) {
        
        //
//        shouldAutoplay = isAutoPlay
        playbackTime = currentPlaybackTime
        
        // 1. 创建播放器
        player = PlayerCtrl(contentURL: fileURL, with: IJKFFOptions.byDefault())
        insertSubview((player?.playerView)!, at: 0)
        
        player?.playerView.bounds = bounds
        player?.playerView.center = CGPoint(x: bounds.midX, y: bounds.midY)
        player?.shouldAutoplay = isAutoPlay
        
        if isAutoPlay {
            print("准备好自动播放")
            // 添加定时器
            
            removeDisplayLink()
            addDisplayLink()
            
        }

        player?.prepareToPlay()
    }
    
}

extension IJKPlayerView {
    func installMovieNotiObservers() {
        
        let notiCenter = NotificationCenter.default
        
        // 加载状态
        notiCenter.addObserver(self, selector: #selector(loadStateDidChange(_:)), name: NSNotification.Name.IJKMPMoviePlayerLoadStateDidChange, object: player)
        
        // 播放完成
        notiCenter.addObserver(self, selector: #selector(moviePlayBackFinish(_:)), name: NSNotification.Name.IJKMPMoviePlayerPlaybackDidFinish, object: player)
        
        // 是否可播放
        notiCenter.addObserver(self, selector: #selector(mediaIspreparedToPlayDidChange(_:)), name: NSNotification.Name.IJKMPMediaPlaybackIsPreparedToPlayDidChange, object: player)
        
        // 播放状态
        notiCenter.addObserver(self, selector: #selector(moviePlayBackStateDidChange(_:)), name: NSNotification.Name.IJKMPMoviePlayerPlaybackStateDidChange, object: player)
    }

    @objc func loadStateDidChange(_ noti: Notification) {

        let loadState = player?.loadState
        if loadState == IJKMPMovieLoadState.playthroughOK {
            print("playthroughOK")
        
        } else if (loadState == IJKMPMovieLoadState.stalled) {
            print("stalled")
        
        } else {
            print("loadState:\(String(describing: loadState))")
        }
    }
    
    // MARK:- 播放停止
    @objc func moviePlayBackFinish(_ noti: Notification) {
        
        guard let reason = noti.userInfo?[IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] as? Int else { return }
        guard let state = IJKMPMovieFinishReason(rawValue: reason) else { return }
        
        switch state {
        case .playbackEnded:
            // 有时候不进
            print("playbackEnded")
            playbackTime = player?.duration
            
            // 设为100%
            playerToolView.progress = 1.0
            playerToolView.sliderView.value = 1.0
            
            // 播放完成
            playSpecificStatusCallback?(false)

        case .playbackError:
            print("playbackError")
        case .userExited:
            print("userExited")
        }
    }
    
    @objc func mediaIspreparedToPlayDidChange(_ noti: Notification) {
        print("准备播放状态改变")
        
        // 还原之前 currentPlaybackTime
        if playbackTime != nil && playbackTime > 0 {
            player?.currentPlaybackTime = playbackTime
        }
        
        
        if let duration = player?.duration {
            print("准备好不播放")
            playerToolView.timeLabel.text = self.timeString()
            self.playerToolView.progress = Float(playbackTime/duration)
        }
        
    }
    
    // MARK:- 播放状态改变
    @objc func moviePlayBackStateDidChange(_ noti: Notification) {
        guard let state = player?.playbackState else { return }
        switch state {
        case .stopped:
            print("player 停止")
            removeDisplayLink()
            playerToolView.playBtn.isSelected = false
            
            isPlaying = false

            // 播放完成 添加 centerPlayBtn
//            centerPlayBtn.center = CGPoint(x: bounds.midX, y: bounds.midY)
            addSubview(centerPlayBtn)
            
        case .playing:
            
            // 对应.paused： 中的 "// 有时候不进 playbackEnded"
            if player?.currentPlaybackTime == player?.duration { return }
            
            print("player 播放")
            addDisplayLink()
            playerToolView.playBtn.isSelected = true
            
            // 移除 centerPlayBtn
            centerPlayBtn.removeFromSuperview()
            
            // 传值
            playSpecificStatusCallback?(true)
            
        case .paused:
            print("player 暂停")
            // 播放完成
            playSpecificStatusCallback?(false)
            
            // 防止加载时不顺时，自动调用(这种情况后面全出现继续播放，但不会通知此方法)
            if isTapPause {
                isTapPause = false
                
                removeDisplayLink()
                playerToolView.playBtn.isSelected = false
                
                // 添加 centerPlayBtn
//                centerPlayBtn.center = CGPoint(x: bounds.midX, y: bounds.midY)
                addSubview(centerPlayBtn)
            } else {
                
                // 有时候不进 playbackEnded
                if player?.currentPlaybackTime == player?.duration {
                    // 设为100%
//                    playerToolView.progress = 1.0
                    playerToolView.playBtn.isSelected = false
                    
                    // 播放完成后，旋转，点击中心按钮时，因是先时移到整个时间最后，但未调用通知 “moviePlayBackFinish” playbackEnded，导致点击播放按钮后会继续播放最后，即直接调用 moviePlayBackFinish 通知，后再次点击才可重新播放，（但有一未解，点击工具条中播放按钮却可）
                    player?.play()
                    
                    addSubview(centerPlayBtn)
                }
            }
            
            
        case .interrupted:
            print("player 中断")
            removeDisplayLink()
            playerToolView.playBtn.isSelected = false
            
            isPlaying = false
            
        case .seekingForward:
            print("player 前移")
            removeDisplayLink()
            
        case .seekingBackward:
            print("player 后移")
            removeDisplayLink()
        }
    }
}

extension IJKPlayerView {
    
    func timeString() -> String {
        // CMTime -> Seconds
//        if let durSec = player?.duration, let curSec = player?.currentPlaybackTime {
        if let durSec = player?.duration, let curSec = playbackTime {
//            curSec = curSec - TimeInterval(1)
            print("\(#file)的\(#function)方法在第\(#line)行：总时长=\(durSec) 当前时间=\(curSec)")
            print("更新时间1>>>>>>\(videoTimeStr(curSec, duration: durSec))")
            return videoTimeStr(curSec, duration: durSec)
        } else {
            print("更新时间2>>>>>\(playerToolView.timeLabel.text!)")
            return playerToolView.timeLabel.text!
        }
    }
    
    
    func videoTimeStr(_ currentTime: TimeInterval, duration: TimeInterval) -> String {
        
        if duration.isNaN || currentTime.isNaN { return "00:00/00:00"}
        
        // 总时长
        let dMin: Int = Int(duration) / 60
        let dSec: Int = Int(duration) % 60
        
        // 当前播放时长
        let cMin: Int = Int(currentTime) / 60
        let cSec: Int = Int(currentTime) % 60
        
        // 转为String
        let durStr = String(format: "%02zd:%02zd", dMin, dSec)
        let curStr = String(format: "%02zd:%02zd", cMin, cSec)
        
        return curStr + "/" + durStr
    }
}
